Schematic execution flow

The following table shows the program flow when a WHDLoad installed program will be executed. I hope it helps to understand how WHDLoad works and how WHDLoad, the Slave and the installed program does cooperate.

The USER
  • starts the demo or game by clicking a Icon or by starting WHDLoad via the command line
The Operating System
  • loads the WHDLoad executable and starts it
WHDLoad
  • checks the Software and Hardware environment
  • loads and checks the Slave
  • allocates required memory for the installed program
  • if PreLoad/S is enabled it loads disk images and files into the RAM (as far as free memory is available)
  • switches OS off (disables mutitasking and interrupts, degrades graphics hardware to OCS, inits all hardware with defined values)
  • jumps into Slave
Slave
  • loads the main executable of the installed program by calling a WHDLoad function (e.g. resload_DiskLoad or resload_LoadFile)
  • patches the main executable (that the program will load his data via the Slave, to fix compatibility problems, to enable an exit from the program)
  • calls the main executable
Installed program
  • will do his stuff
  • on loading data from disk it will call the Slave (because the Slave has patched it in this way previously), and the Slave will call WHDLoad, and WHDLoad will partially enable the OS to load the data (only if the data is not PreLoad'ed), then return, return and the installed program continues
The USER
  • exits the program by pressing the QuitKey
Slave
WHDLoad
  • re-enables the OS (restores hardware registers, display and memory)
  • frees all allocated resources
  • returns to the OS

How to install a simple one disk trackloader

This is a very small and short step by step guide on how to create an install using WHDLoad. The guide reflects an ideal simple case. In the real such a case will probably never occur. For special cases and problems, read the chapters that follow this.
  1. Prework
  2. The Slave
    To write the slave we need following information:
    1. Where on disk is the main executable located?
    2. Where inside the main executable is the disk loader located?
    To get this information we first analyze the bootblock. Most times the main executable will be loaded from here via exec.DoIO(). Sometimes a special trackloader is in the bootblock. We now write a Slave which will simulates the bootblock and loads the main executable from the disk image. Now we rip the main executable from the image or a memory dump. After that we have to find the loader in the main exe. A fast way is to search for the pattern $AAAAAAAA (used by MFM decoding) with a hex-editor. Then cut the area (+/- $1000 bytes) found, disassemble it, and search the start of the routine. Understand the parameterlist. Now we create code for the Slave which will patch this loader routine in a way that all calls to the loader will be redirected to the Slave. The Slave will then adjust the parameters and call the WHDLoad function resload_DiskLoad.
  3. In the ideal case the install is now complete.
    The only thing left to do is to create a nice Icon. Rip two pictures using the snoop feature of WHDLoad and SP or a freezer or U.A.E. and build the icon. The 16 colour RomIcon palette is recommended.

Possible problems and special cases

Non standard trackloader

Some programs use their very own disk format. This means that DIC is unable to create the disk images. To create files or images from such disk the use of RawDIC is recommended. See documentation of RawDIC for more information.

Multiple disks

If the program uses more than one disk the slave must redirect the disk accesses to the appropriate image file. Sometimes this is not easy. Some programs support more than one drive, so you can use the drive number for selecting the disk. Most programs use an ID on every disk to distinguish them. In this case, use a variable which holds the disk number, and on every access to the disk ID (determine such an access by analyzing the parameters for the disk loader) increase the variable (if last disk is reached, decrease it). So hopefully the loader will read the ID again and again up until the correct disk is inserted. Perhaps there is a request from the program that the user should insert the right disk, disable it.

Highscore saving

Not much to say here. Use resload_SaveFile to write the appropriate memory area to the disk. If you like, encrypt it a bit so lamers can't patch it too easily. It is not recommended to write directly into disk images (using resload_SaveFileOffset), because if something goes wrong (e.g. crash) it's possible that the images will be damaged.

Savegames

Savegame handling is the same as with highscores.

Accesses to the operating system

At the time the slave and the installed program is executed, absolutely no OS exist nor is accessible nor makes any sense to access them! Therefore all accesses which the installed program does must be disabled. If there aren't many of them, and they don't makee sense in the WHDLoad environment (like exec.Disable() or exec.SuperState()) simply NOP ($4e71) them. If the accesses have an important function (like exec.DoIo()), redirect them to the slave and emulate them. If there are loads of them, create a simple exec.library in an unused memory area (set $4 to this). (e.g. Oscar.slave emulates exec.AllocMem()) To detect such accesses, the initial execbase is set to $f0000001 with the intention that all routines which like to use the execbase will force an "Address Error" exception.

Common compatibility problems

Limited address space on 68000/68010/68ec020

On these processors the address space is limited to 16MB ($000000...$ffffff) because these CPU's have only 24 address lines. As a result all accesses to higher spaces are performed to the lower 16MB and the most significant 8 bits are ignored. Some programs use these bits to store data, or simply forgets to clear them. On a processor with full 4 GB address space like 68020/680ec30/68030/68040/68060 this will not work, because the full 32bit address will be accessed.
To solve this you have to patch these accesses and redirect them to the appropriate address.
Sometimes the reason for accesses to strange addresses may be an uninitialized pointer. In this case it may help to clear $400 - ws_BaseMemSize.

Different stackframes on each processor

The stackframes created by the processor on interrupts and exceptions are different for the members of the 68k family. On the 68000 a stackframe is 6 bytes, except on Bus and Address Errors. The stackframe contains the saved SR at (a7) and the saved PC at (2,a7). On all other processors (68010+) the minimal stackframe is 8 bytes and additionally contains the vector number as a word at (6,a7). This Four-Word stackframe format $0 is created for "Trap #xx" and Interrupts on 68010-68060. The stackframes on other exceptions are different on each processor. The RTE instruction works differently on the 68000 against 68010+. On a 68000 it simply restores the SR and PC and continues program execution at the interrupted address. On the 68010+ it will additionally free the stackframe depending on the stackframe format.
Some programs push an address (PC) and an SR and then execute an RTE instruction. This works on a 68000 only, on 68010+ this will have undefinable results.
If a program does so, you'll have to fix this stuff. Sometimes it may be enough to replace the RTE with a RTR.

MOVEM.x RL,-(An) on 68000/010 and 68020/030/040

There is a difference if the register used in predecrement mode is also contained in the register list. For the 68020, 68030 and 68040 the value written to memory is the initial register value decemented by the size of the operation. The 68000 and 68010 write the initial register value (not decremented).
Because such a construction is not very useful, no current software is known to have problems due to this.

General guidelines for writing installs

Tips & tricks

What's better, using diskimages or files ?

Sometimes you will have the choice to use disk images or real files. Both have advantages. The use of disk images is usually the easier and faster way to create the slave. But real files are more easily cached (if there is very little memory or the memory is fragmented, diskimages cannot be cached). The needed space on harddisk will also be smaller with real files than with disk images. You should only use disk images if there are a lot of files (more than 30).